package com.bidevalution.support.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.util.Collections;

public class RedisLockTool {
    private static final Logger logger = LoggerFactory.getLogger(RedisLockTool.class);

    //加锁成功标志
    private static final String LOCK_SUCCESS = "OK";
    //解锁成功标志
    private static final String RELEASE_SUCCESS = "1";
    //加锁标志
    private static final String SET_IF_NOT_EXIST = "NX";
    //给锁设置过期时间的标志 EX(秒) PX(毫秒)
    private static final String SET_WITH_EXPIRE_TIME = "EX";


    /**
     * 尝试获得锁
     * @param jedis    redis实例
     * @param key      具体的锁
     * @param value    锁的值，解锁的时候用
     * @param expTime  锁的失效时间
     * @return 加锁成功标志
     */
    public  static boolean getDistributedLock(Jedis jedis, String key, String value, int expTime){
        boolean isLocked = false;
        try {
            String result = jedis.set(key, value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expTime);
            if (LOCK_SUCCESS.equals(result)) {
                isLocked = true;
            }
        } catch (Exception e) {
            logger.error("redis加锁失败："+e.getMessage());
        }finally {
            if(jedis != null){
                jedis.close();
            }
        }
        return isLocked;
    }

    public static boolean lock(Jedis jedis, String key, String value, int expTime){
        boolean b = getDistributedLock(jedis, key, value, expTime);
        while(!b){
            b = getDistributedLock(jedis, key, value, expTime);
            if(b){
                jedis.close();
                return b;
            }
        }
        jedis.close();
        return b;
    }
    /**
     * 尝试解锁(删除key)
     * @param jedis  redis实例
     * @param key    具体的锁
     * @param value
     * @return
     */
    public static boolean releaseDistributedLock(Jedis jedis, String key, String value){
        boolean isUnlocked = false;
        try {
            //获取锁对应的value值，检查是否与requestId相等，如果相等则删除锁（解锁);eval()方法执行Lua脚本是原子性的
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(key), Collections.singletonList(value));
            if((null != result) && RELEASE_SUCCESS.equals(result.toString())){
                isUnlocked = true;
            }
        } catch (Exception e) {
            logger.error("redis解锁异常:"+e.getMessage());
        }finally {
            jedis.close();
        }
        return isUnlocked;
    }


}
